package com.bwie.service.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.bwie.mapper.TbActiveRuleMapper;
import com.bwie.mapper.TbWinRecordMapper;
import com.bwie.pojo.TbActive;
import com.bwie.pojo.TbActiveRule;
import com.bwie.pojo.TbWinRecord;
import com.bwie.service.IUserService;
import com.bwie.service.TbActiveService;
import com.bwie.mapper.TbActiveMapper;
import com.bwie.utils.R;
import com.bwie.utils.TokenUtils;
import com.bwie.vo.PageInfoVo;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.kafka.core.KafkaTemplate;
import org.springframework.kafka.support.Acknowledgment;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
* @author andy
* @description 针对表【tb_active(抽奖活动表)】的数据库操作Service实现
* @createDate 2025-07-02 11:36:42
*/
@Service
public class TbActiveServiceImpl extends ServiceImpl<TbActiveMapper, TbActive>
    implements TbActiveService{

    @Autowired
    HttpServletRequest request;

    @Autowired
    TbActiveMapper tbActiveMapper;

    @Autowired
    TbActiveRuleMapper tbActiveRuleMapper;

    @Autowired
    TbWinRecordMapper tbWinRecordMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    IUserService iUserService;

    @Autowired
    RedissonClient redissonClient;

    @Autowired
    KafkaTemplate kafkaTemplate;

    @Override
    public R getActiveList(PageInfoVo pageInfoVo) {
        //--1 构造分页参数
        Page<TbActive> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

        //--2 分页查询
//        Page<TbActive> tbActivePage = tbActiveMapper.selectPage(page, null);
        Page<TbActive> tbActivePage = tbActiveMapper.getActiveList(page, pageInfoVo);

        return R.ok().setData(tbActivePage);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R addActive(TbActive tbActive) {
        String token = request.getHeader("token");
        if(token == null) {
            return R.error().setMsg("请先登录");
        }

        //--1 添加抽奖活动

        // 处理开始时间和截止时间
        try {
            List<String> activeTime = tbActive.getActiveTime();
            SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            tbActive.setBeginTime(format.parse(activeTime.get(0)));
            tbActive.setEndTime(format.parse(activeTime.get(1)));
        } catch (ParseException e) {
            throw new RuntimeException(e);
        }

        // 审计字段
        String userName = TokenUtils.getUserName(token);
        tbActive.setCreateBy(userName);
        tbActive.setCreateTime(new Date());

        tbActiveMapper.insert(tbActive);

        //--2 添加抽奖活动规则
        for (TbActiveRule tbActiveRule : tbActive.getRuleList()) {
            tbActiveRule.setActiveId(tbActive.getActiveId());

            // 审计字段
            tbActiveRule.setCreateBy(userName);
            tbActiveRule.setCreateTime(new Date());

            tbActiveRuleMapper.insert(tbActiveRule);
        }

        return R.ok();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public R joinActive(Integer activeId) {
        //--1 获取用户ID
        String token = request.getHeader("token");
        if(token == null) {
            return R.error().setMsg("请先登录");
        }
        Integer userId = TokenUtils.getUserId(token);

        //--2 获取活动的信息
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if(tbActive == null) {
            return R.error().setMsg("活动不存在");
        }

        // 检查活动状态
        if(tbActive.getActiveStatus() != 0) {
            return R.error().setMsg("活动已结束，谢谢参与！！！");
        }

        // 根据活动起止时间，判断活动是否开始
        long currentTimeMillis = System.currentTimeMillis();
        if(currentTimeMillis < tbActive.getBeginTime().getTime()) {
            return R.error().setMsg("活动未开始，请耐心等待！！！");
        }
        if(currentTimeMillis > tbActive.getEndTime().getTime()) {
            return R.error().setMsg("活动已结束，谢谢参与！！！");
        }

        //
        //-- 检查用户是否有资格抽奖
        // join-activeId-userId(join-5-3)
        String joinKey = "join-" + activeId + "-" + userId;
        Boolean hasJoinKey = stringRedisTemplate.hasKey(joinKey);
        if(!hasJoinKey) {
            // 说明从来没有参与过
            stringRedisTemplate.opsForValue().set(joinKey, ""+tbActive.getFreeTimes());
        }
        else {
            // 说明用户参与过
        }
        // decrement = -1
        Long times = stringRedisTemplate.opsForValue().decrement(joinKey);
        if(times < 0) {
            return R.error().setMsg("您已经没有抽奖的次数，请勿重复参与！！！");
        }

        String activeKey = "active-" + activeId;
        Boolean hasKey = stringRedisTemplate.hasKey(activeKey);
        if(!hasKey) {
            // 活动数据还没加载，加载活动数据
            List<TbActiveRule> tbActiveRules = tbActiveRuleMapper.selectList(
                    new QueryWrapper<TbActiveRule>().lambda().eq(TbActiveRule::getActiveId, activeId)
            );

            // 把活动规则放入缓存
            ArrayList<String> list = new ArrayList<>();
            for (TbActiveRule tbActiveRule : tbActiveRules) {
                list.add(""+tbActiveRule.getRuleId());
            }

            // 填充100个规则，如果ID为0，表示没有中奖，如果ID不为0，表示中奖
            while(list.size() < 100) {
                list.add("0");
            }

            // 打乱列表顺序
            Collections.shuffle(list);

            // 把打乱后的数据，放入redis的list中
            stringRedisTemplate.opsForList().leftPushAll(activeKey, list);
        }

        //--3 抽奖
        String s = stringRedisTemplate.opsForList().rightPop(activeKey);
        if(s == null) {
            // 奖品已抽光，设置活动已经停止
            tbActive.setActiveStatus(1);
            tbActive.setUpdateBy(TokenUtils.getUserName(token));
            tbActive.setUpdateTime(new Date());
            tbActiveMapper.updateById(tbActive);
            return R.error().setMsg("奖品已抽光，谢谢参与！！！");
        }
        TbWinRecord tbWinRecord = new TbWinRecord();
        if(s.equals("0")) {
            // 没有中奖
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(0);
            tbWinRecord.setRecordDesc("未中奖");
            tbWinRecord.setActiveType(tbWinRecord.getActiveType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(TokenUtils.getUserName(token));
            tbWinRecord.setCreateTime(new Date());

            tbWinRecordMapper.insert(tbWinRecord);
            return R.ok().setData(tbWinRecord).setMsg("感谢您的参与，此次抽奖您未中奖");
        }
        else {
            // 中奖
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(Integer.valueOf(s));
            tbWinRecord.setRecordDesc("已中奖");
            tbWinRecord.setActiveType(tbWinRecord.getActiveType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(TokenUtils.getUserName(token));
            tbWinRecord.setCreateTime(new Date());

            Integer ruleId = Integer.valueOf(s);
            TbActiveRule tbActiveRule = tbActiveRuleMapper.selectById(ruleId);

            tbWinRecordMapper.insert(tbWinRecord);
            return R.ok().setData(tbWinRecord).setMsg("感谢您的参与，此次抽奖已中奖，商品是:" + tbActiveRule.getWinProd());
        }
    }

    @Override
    public R getJoinRecord(PageInfoVo pageInfoVo) {
        //--1 构造分页参数
        Page<TbWinRecord> page = new Page<>(pageInfoVo.getPageNum(), pageInfoVo.getPageSize());

        //--2 分页查询
        Page<TbWinRecord> tbWinRecordPage = tbWinRecordMapper.getJoinRecordList(page, pageInfoVo);

        return R.ok().setData(tbWinRecordPage);
    }

    private R doJoinActiveByScore(Integer activeId) {
        //--1 获取用户ID
        String token = request.getHeader("token");
        if(token == null) {
            return R.error().setMsg("请先登录");
        }
        Integer userId = TokenUtils.getUserId(token);

        //--2 获取活动的信息
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if(tbActive == null) {
            return R.error().setMsg("活动不存在");
        }

        // 检查活动状态
        if(tbActive.getActiveStatus() != 0) {
            return R.error().setMsg("活动已结束，谢谢参与！！！");
        }

        // 根据活动起止时间，判断活动是否开始
        long currentTimeMillis = System.currentTimeMillis();
        if(currentTimeMillis < tbActive.getBeginTime().getTime()) {
            return R.error().setMsg("活动未开始，请耐心等待！！！");
        }
        if(currentTimeMillis > tbActive.getEndTime().getTime()) {
            return R.error().setMsg("活动已结束，谢谢参与！！！");
        }

        //
        //-- 检查用户是否有资格抽奖
        // 抽奖扣减积分
        Integer payScore = tbActive.getPayScore();
        R r = iUserService.joinActiveSubScore(userId, payScore);
        if(r.getCode() != 200) {
            return r;
        }

        String activeKey = "active-" + activeId;
        Boolean hasKey = stringRedisTemplate.hasKey(activeKey);
        if(!hasKey) {
            // 活动数据还没加载，加载活动数据
            List<TbActiveRule> tbActiveRules = tbActiveRuleMapper.selectList(
                    new QueryWrapper<TbActiveRule>().lambda().eq(TbActiveRule::getActiveId, activeId)
            );

            // 把活动规则放入缓存
            ArrayList<String> list = new ArrayList<>();
            for (TbActiveRule tbActiveRule : tbActiveRules) {
                list.add(""+tbActiveRule.getRuleId());
            }

            // 填充100个规则，如果ID为0，表示没有中奖，如果ID不为0，表示中奖
            while(list.size() < 100) {
                list.add("0");
            }

            // 打乱列表顺序
            Collections.shuffle(list);

            // 把打乱后的数据，放入redis的list中
            stringRedisTemplate.opsForList().leftPushAll(activeKey, list);
        }

        //--3 抽奖
        String s = stringRedisTemplate.opsForList().rightPop(activeKey);
        if(s == null) {
            // 奖品已抽光，设置活动已经停止
            tbActive.setActiveStatus(1);
            tbActive.setUpdateBy(TokenUtils.getUserName(token));
            tbActive.setUpdateTime(new Date());
            tbActiveMapper.updateById(tbActive);
            return R.error().setMsg("奖品已抽光，谢谢参与！！！");
        }
        TbWinRecord tbWinRecord = new TbWinRecord();
        if(s.equals("0")) {
            // 没有中奖
            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(0);
            tbWinRecord.setRecordDesc("未中奖");
            tbWinRecord.setActiveType(tbWinRecord.getActiveType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(TokenUtils.getUserName(token));
            tbWinRecord.setCreateTime(new Date());

            tbWinRecordMapper.insert(tbWinRecord);
            return R.ok().setData(tbWinRecord).setMsg("感谢您的参与，此次抽奖您未中奖");
        }
        else {
            // 中奖,用户中奖则使用mg异步记录抽奖记录



            tbWinRecord.setUserId(userId);
            tbWinRecord.setRuleId(Integer.valueOf(s));
            tbWinRecord.setRecordDesc("已中奖");
            tbWinRecord.setActiveType(tbWinRecord.getActiveType());
            tbWinRecord.setWinFlag(0);
            tbWinRecord.setActiveId(activeId);
            tbWinRecord.setCreateBy(TokenUtils.getUserName(token));
            tbWinRecord.setCreateTime(new Date());

            Integer ruleId = Integer.valueOf(s);
            TbActiveRule tbActiveRule = tbActiveRuleMapper.selectById(ruleId);

            // 发送kafka消息
            kafkaTemplate.send("topic-record", JSON.toJSONString(tbWinRecord));

//            tbWinRecordMapper.insert(tbWinRecord);
            return R.ok().setData(tbWinRecord).setMsg("感谢您的参与，此次抽奖已中奖，商品是:" + tbActiveRule.getWinProd());
        }
    }

    @KafkaListener(topics = "topic-record")
    public void recvRecordMessage(String message, Acknowledgment acknowledgment) {
        // 接收并转换消息
        System.out.println("kafka接收到消息:" + message);
        TbWinRecord tbWinRecord = JSON.parseObject(message, TbWinRecord.class);

        // 保存中奖记录
        tbWinRecordMapper.insert(tbWinRecord);

        // 手动确认消息
        acknowledgment.acknowledge();
    }

    @Override
    public R joinActiveByScore(Integer activeId) {
        // 获取分布式锁
        String lockKey = "activeId-" + activeId;
        RLock rLock = redissonClient.getLock(lockKey);
        try {
            // 加锁
            rLock.lock();

            // 积分抽奖
            return doJoinActiveByScore(activeId);
        }
        catch (Exception e) {
            e.printStackTrace();
            return R.error().setMsg("系统异常");
        }
        finally {
            // 解锁一定要在finally中
            rLock.unlock();
        }



    }

    @Override
    public R getActiveById(Integer activeId) {
        //--1
        TbActive tbActive = tbActiveMapper.selectById(activeId);
        if (tbActive == null) {
            return R.error().setMsg("活动不存在");
        }

        //--2

        return R.ok().setData(tbActive);
    }
}




